package reflection;

import netty.RpcRequest;
import org.springframework.cglib.reflect.FastClass;
import org.springframework.cglib.reflect.FastMethod;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Date;

/**
 * @Author: dch
 * @Date: 2020/5/15 11:28
 * @Description:
 */
public class ReflectionDemo {
    public static void main(String[] args) throws Exception {
        //"正射"
        //实例化
        ArrayList list = new ArrayList();
        //执行方法
        list.add("reflection");
        System.out.println(list.get(0));

        //反射
        //使用 Class 类中的 forName() 静态方法获取字节码文件对象
        Class clazz = Class.forName("java.util.ArrayList");
        System.out.println("【Class】"+clazz);

        //获取ArrayList类的add方法
        Method method_add = clazz.getMethod("add",Object.class);
        System.out.println("【Method】"+method_add);

        //获取ArrayList类的构造器
        Constructor constructor = clazz.getConstructor();
        System.out.println("【Constructor】"+constructor);

        String name = method_add.getDeclaringClass().getName();
        System.out.println("【通过方法反射得到class】"+name);


        //使用CGLB Reflect
        FastClass fastClass = FastClass.create(clazz);
//        Class<?>[] parameterTypes = RpcRequest.getParameterTypes();
//        FastMethod fastMethod = fastClass.getMethod("add",parameterTypes);

        //用 newInstance() 创建新的对象
        Object object = constructor.newInstance();

        //使用 invoke() 方法调用对象中的add方法
        method_add.invoke(object, "reflection");

        //获取ArrayList类的get方法法
        Method method_get = clazz.getMethod("get",int.class);

        //使用CGLB Reflect
        FastClass fastClass1 = FastClass.create(clazz);
        FastMethod fastMethod = fastClass1.getMethod("get",int.class.getClasses());
//        fastMethod.invoke(serviceBean, parameters);

        //使用 invoke() 方法调用对象中的get方法 object.get(0) ==> list.get(0)
        Object value = method_get.invoke(object, 0);
        System.out.println(value);

        Class<?> userClass = Class.forName("reflection.User");
        System.out.println(userClass);
        Class<?> usClass = Class.forName("main.java.reflection.UserService");
        System.out.println(usClass);

        //获取Person类的class对象
        Class clazz1 = Class.forName("main.java.reflection.Person");
        //获取Person类的所有方法信息
        System.out.println("=====获取Person类的所有方法信息=====");
        Method[] methods = clazz1.getDeclaredMethods();
        for(Method method:methods){
            System.out.println(method.toString());
        }
        //获取Person类的所有成员属性信息
        System.out.println("=====获取Person类的所有成员属性信息=====");
        Field[] fields = clazz1.getDeclaredFields();
        for(Field field:fields){
            System.out.println(field.toString());
        }
        //获取Person类的所有构造方法信息
        System.out.println("=====获取Person类的所有构造方法信息====");
        Constructor[] constructors = clazz1.getDeclaredConstructors();
        for(Constructor constructor1:constructors){
            System.out.println(constructor1.toString());
        }
        /*
        * **Class 对象的 newInstance()**
        *使用 Class 对象的 newInstance()方法来创建该 Class 对象对应类的实例，但是这种方法要求该 Class 对象对应的类有默认的空构造器。
        *调用 Constructor 对象的 newInstance()
        *先使用 Class 对象获取指定的 Constructor 对象，再调用 Constructor 对象的 newInstance()方法来创建 Class 对象对应类的实例,
        * 通过这种方法可以选定构造方法创建实例。
        * */

        //获取Person类的Class对象
        Class clazz2 = Class.forName("main.java.reflection.Person");
        //使用.newInstance()创建对象(必须由默认的空构造器)
        main.java.reflection.Person o = (main.java.reflection.Person) clazz2.newInstance();
        System.out.println("person="+o);

        //使用构造器方法创建对象
        Constructor constructor2 = clazz2.getDeclaredConstructor(String.class,Integer.class, Date.class);
        main.java.reflection.Person person1 = (main.java.reflection.Person)constructor2.newInstance("zs",28,new Date());
        System.out.println("person1="+person1);

        // 优点：**在运行时动态获取类和对象中的内容，极大地提高系统的灵活性和扩展性；很多框架（mybatis、spring、springmvc等）
        // 中都用到了反射机制，可以说反射是框架设计的灵魂。
        //**缺点：**会有一定的性能损耗，JVM 无法对这些代码进行优化；破坏类的封装性。

    }
}
